Skip to content

Commit

Permalink
add: scene transitions
Browse files Browse the repository at this point in the history
This commits brings now full support for transition, adding them to the scenes.
  • Loading branch information
ThePedroo committed Aug 4, 2023
1 parent 3dd2335 commit b30724a
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 37 deletions.
8 changes: 4 additions & 4 deletions OS_SUPPORT.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,14 +137,14 @@ Spoiler (Not confirmed): We're planning to use JS, HTML and CSS to make the VN m
This is the list of features that we're planning to add (or modify) to PerforVNM in the future.

- [x] Scenes (Completed)
- [x] Characters (Missing full animations)
- [x] Animations (Partial, only character movement)
- [x] Scenarios (Completed)
- [x] Menu (Missing vertical footer)
- [x] Speech (Completed)
- [x] Music (Completed)
- [x] Transitions (Completed)
- [x] Characters (Missing full animations)
- [x] Animations (Partial, only character movement)
- [x] Menu (Missing vertical footer)
- [x] Sound effects (Missing support for more than 1 sound effect)
- [x] Transitions (Menu -> about/settings only)
- [x] Settings (Misses some additional configurations)
- [ ] Custom paths (High Priority)
- [ ] Save/Load system (High Priority)
Expand Down
29 changes: 23 additions & 6 deletions android/app/src/main/java/com/perforvnm/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ class MainActivity : ComponentActivity() {
}
}, length - "PerforVNM".length, length, 0)
append("1.16.2-b.0 (code generator), 1.15.8-b.0 (generated code).")
append("\n\n This is our example visual novel, made by @ThePedroo")
append("\n\nThis is our example visual novel, made by @ThePedroo")
}
textView.textSize = 15f
textView.setTextColor(0xFFFFFFFF.toInt())
Expand Down Expand Up @@ -821,12 +821,19 @@ class MainActivity : ComponentActivity() {
val frameLayout = FrameLayout(this)
frameLayout.setBackgroundColor(0xFF000000.toInt())

val animationFadeIn = AlphaAnimation(0f, 1f)
animationFadeIn.duration = 1000
animationFadeIn.interpolator = LinearInterpolator()
animationFadeIn.fillAfter = true

val imageView_scenario = ImageView(this)
imageView_scenario.setImageResource(R.raw.background_thanking)
imageView_scenario.scaleType = ImageView.ScaleType.FIT_CENTER

frameLayout.addView(imageView_scenario)

imageView_scenario.startAnimation(animationFadeIn)

val imageView_Pedro = ImageView(this)
imageView_Pedro.setImageResource(R.raw.pedro_staring)
imageView_Pedro.scaleType = ImageView.ScaleType.FIT_CENTER
Expand All @@ -842,11 +849,21 @@ class MainActivity : ComponentActivity() {

frameLayout.addView(imageView_Pedro)

imageView_Pedro.animate()
.translationX(200.toFloat())
.translationY(0.toFloat())
.setDuration(1000)
.start()
imageView_Pedro.startAnimation(animationFadeIn)

animationFadeIn.setAnimationListener(object : Animation.AnimationListener {
override fun onAnimationStart(animation: Animation?) {}

override fun onAnimationEnd(animation: Animation?) {
imageView_Pedro.animate()
.translationX(200f)
.translationY(0f)
.setDuration(1000)
.start()
}

override fun onAnimationRepeat(animation: Animation?) {}
})

mediaPlayer = MediaPlayer.create(this, R.raw.menu_music)

Expand Down
6 changes: 4 additions & 2 deletions docs/scene/addCharacter.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ scene.addCharacter(scene, {
top: 0
}
},
animateTo: {
animation: {
side: 'right',
duration: 1000
margins: {
side: 100,
top: 0
Expand All @@ -39,8 +40,9 @@ scene.addCharacter(scene, {
- `margins`: The margin of the character can be any number. An object with the following properties: (Not required if side == center)
- `side`: The margin of the side of the character.
- `top`: The margin of the top of the character.
- `animateTo`: The animation of the character. An object with the following properties:
- `animation`: The animation of the character. An object with the following properties:
- `side`: The side of the character can be `left`, `right` or `center`.
- `duration`: The duration of the animation.
- `margins`: The margin of the character can be any number. An object with the following properties: (Not required if side == center)
- `side`: The margin of the side of the character.
- `top`: The margin of the top of the character.
Expand Down
29 changes: 29 additions & 0 deletions docs/scene/addTransition.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Scene - Add transition

## Description

Adds a fade in transition to the scenes when entering the scene.

## Syntax

```js
scene.addTransition(scene, { duration: 1000 })
```

## Parameters

- `scene`: The scene configurations from the `init` function.
- `duration`: The duration of the transition.

## Return value

This function will return the scene configurations if the addition was successful, otherwise, it will execute `process.exit(1)` to terminate the generation process.

## Platform support

- [x] Android
- [ ] iOS
- [ ] Windows
- [ ] Linux distros
- [ ] MacOS
- [ ] Web
2 changes: 1 addition & 1 deletion src/coder.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import helper from './helper.js'

global.visualNovel = { menu: null, info: null, internalInfo: {}, code: '', scenes: [], customXML: [] }
global.PerforVNM = {
codeGeneratorVersion: '1.16.2-b.0',
codeGeneratorVersion: '1.17.2-b.0',
generatedCodeVersion: '1.15.8-b.0',
repository: 'https://github.com/PerformanC/PerforVNMaker'
}
Expand Down
6 changes: 4 additions & 2 deletions src/perforvnm.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,18 @@ firstScene = scene.addCharacter(firstScene, {
position: {
side: 'center'
},
animateTo: {
animation: {
side: 'left',
duration: 1000,
margins: {
side: 200,
top: 0
}
}
}) /* Adds a character to the scene */
firstScene = scene.addScenario(firstScene, { image: 'background_thanking' }) /* Adds a scenario to the scene */
firstScene = scene.addSoundEffect(firstScene, { sound: 'menu_music', delay: 1000 })
firstScene = scene.addSoundEffect(firstScene, { sound: 'menu_music', delay: 1000 }) /* Adds a sound effect to the scene at second 1 */
firstScene = scene.addTransition(firstScene, { duration: 1000 }) /* Adds a transition to the scene */
scene.finalize(firstScene, { buttonsColor: 'FFFFFF', footerTextColor: 'FFFFFF' }) /* Writes the scene */

let secondScene = scene.init({ name: 'scene2' })
Expand Down
124 changes: 102 additions & 22 deletions src/scene.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ function init(options) {

console.log('Starting scene.. (Android)')

return { name: options.name, characters: [], background: null, speech: null, effect: null, music: null }
return { name: options.name, characters: [], background: null, speech: null, effect: null, music: null, transition: null }
}

function addCharacter(scene, options) {
Expand Down Expand Up @@ -91,47 +91,59 @@ function addCharacter(scene, options) {
process.exit(1)
}

if (options.animateTo) {
if (!options.animateTo.side) {
console.error(`ERROR: Character animateTo side not provided.\n- Character name: ${options.name}\n- Scene name: ${scene.name}`)
if (options.animation) {
if (!options.animation.side) {
console.error(`ERROR: Character animation side not provided.\n- Character name: ${options.name}\n- Scene name: ${scene.name}`)

process.exit(1)
}

if (!['center', 'left', 'right'].includes(options.animateTo.side)) {
console.error(`ERROR: Character animateTo side not valid, it must be either center, left or right.\n- Character name: ${options.name}\n- Scene name: ${scene.name}`)
if (!['center', 'left', 'right'].includes(options.animation.side)) {
console.error(`ERROR: Character animation side not valid, it must be either center, left or right.\n- Character name: ${options.name}\n- Scene name: ${scene.name}`)

process.exit(1)
}

if (options.animateTo.side != 'center' && options.animateTo.margins?.side == null) {
console.error(`ERROR: Character animateTo side margin not provided.\n- Character name: ${options.name}\n- Scene name: ${scene.name}`)
if (options.animation.side != 'center' && options.animation.margins?.side == null) {
console.error(`ERROR: Character animation side margin not provided.\n- Character name: ${options.name}\n- Scene name: ${scene.name}`)

process.exit(1)
}

if (options.animateTo.side != 'center' && typeof options.animateTo.margins?.side != 'number') {
console.error(`ERROR: Character animateTo side margin must be a number.\n- Character name: ${options.name}\n- Scene name: ${scene.name}`)
if (options.animation.side != 'center' && typeof options.animation.margins?.side != 'number') {
console.error(`ERROR: Character animation side margin must be a number.\n- Character name: ${options.name}\n- Scene name: ${scene.name}`)

process.exit(1)
}

if (options.animateTo.side != 'center' && options.animateTo.margins.top == null) {
console.error(`ERROR: Character animateTo top margin not provided.\n- Character name: ${options.name}\n- Scene name: ${scene.name}`)
if (options.animation.side != 'center' && options.animation.margins.top == null) {
console.error(`ERROR: Character animation top margin not provided.\n- Character name: ${options.name}\n- Scene name: ${scene.name}`)

process.exit(1)
}

if (options.animateTo.side != 'center' && typeof options.animateTo.margins?.top != 'number') {
console.error(`ERROR: Character animateTo top margin must be a number.\n- Character name: ${options.name}\n- Scene name: ${scene.name}`)
if (options.animation.side != 'center' && typeof options.animation.margins?.top != 'number') {
console.error(`ERROR: Character animation top margin must be a number.\n- Character name: ${options.name}\n- Scene name: ${scene.name}`)

process.exit(1)
}

if (options.animation.duration == null) {
console.error(`ERROR: Character animation duratiton not provided.\n- Character name: ${options.name}\n- Scene name: ${scene.name}`)

process.exit(1)
}

if (typeof options.animation.duration != 'number') {
console.error(`ERROR: Character animation duratiton must be a number.\n- Character name: ${options.name}\n- Scene name: ${scene.name}`)

process.exit(1)
}
}

console.log(`Adding character "${options.name}" for scene "${scene.name}".. (Android)`)

scene.characters.push({ name: options.name, image: options.image, position: options.position, animateTo: options.animateTo })
scene.characters.push({ name: options.name, image: options.image, position: options.position, animation: options.animation })

console.log(`Character "${options.name}" added for scene "${scene.name}". (Android)`)

Expand Down Expand Up @@ -299,6 +311,28 @@ function addMusic(scene, options) {
return scene
}

function addTransition(scene, options) {
if (!options?.duration) {
console.error(`ERROR: Scene transition duration not provided.\n- Scene name: ${scene.name}`)

process.exit(1)
}

if (typeof options.duration != 'number') {
console.error(`ERROR: Scene transition duration must be a number.\n- Scene name: ${scene.name}`)

process.exit(1)
}

console.log(`Adding transition for scene "${scene.name}".. (Android)`)

scene.transition = options

console.log(`Transition added for scene "${scene.name}". (Android)`)

return scene
}

function finalize(scene, options) {
if (!options?.buttonsColor) {
console.error(`ERROR: Scene "back" text color not provided.\n- Scene name: ${scene.name}`)
Expand All @@ -325,13 +359,22 @@ function finalize(scene, options) {
' val frameLayout = FrameLayout(this)' + '\n' +
' frameLayout.setBackgroundColor(0xFF000000.toInt())' + '\n\n'

if ((scene.characters.length != 0 || scene.background != '') && scene.transition) {
sceneCode += ' val animationFadeIn = AlphaAnimation(0f, 1f)' + '\n' +
' animationFadeIn.duration = ' + scene.transition.duration + '\n' +
' animationFadeIn.interpolator = LinearInterpolator()' + '\n' +
' animationFadeIn.fillAfter = true' + '\n\n'
}

if (scene.background != '') {
sceneCode += ' val imageView_scenario = ImageView(this)' + '\n' +
' imageView_scenario.setImageResource(R.raw.' + scene.background + ')' + '\n' +
' imageView_scenario.scaleType = ImageView.ScaleType.FIT_CENTER' + '\n\n' +

' frameLayout.addView(imageView_scenario)' + '\n\n'

if (scene.transition)
sceneCode += ' imageView_scenario.startAnimation(animationFadeIn)' + '\n\n'
}

for (let character of scene.characters) {
Expand All @@ -341,7 +384,7 @@ function finalize(scene, options) {
' imageView_' + character.name + '.setImageResource(R.raw.' + character.image + ')' + '\n' +
' imageView_' + character.name + '.scaleType = ImageView.ScaleType.FIT_CENTER' + '\n\n' +

(character.animateTo ? ' val layoutParams_' + character.name + ' = LayoutParams(' + '\n' +
(character.animation ? ' val layoutParams_' + character.name + ' = LayoutParams(' + '\n' +
' LayoutParams.WRAP_CONTENT,' + '\n' +
' LayoutParams.WRAP_CONTENT' + '\n' +
' )' + '\n\n' +
Expand Down Expand Up @@ -394,23 +437,59 @@ function finalize(scene, options) {
}
}

if (character.animateTo) {
switch (character.animateTo.side) {
if (scene.transition) {
sceneCode += '\n' + ' imageView_' + character.name + '.startAnimation(animationFadeIn)' + '\n'

if (character.animation) {
sceneCode += '\n' + ' animationFadeIn.setAnimationListener(object : Animation.AnimationListener {' + '\n' +
' override fun onAnimationStart(animation: Animation?) {}' + '\n\n' +

' override fun onAnimationEnd(animation: Animation?) {' + '\n'

switch (character.animation.side) {
case 'center': {
sceneCode += ' imageView_' + character.name + '.animate()' + '\n' +
' .translationX(((frameLayout.width - imageView_' + character.name + '.width) / 2).toFloat())' + '\n' +
' .translationY(((frameLayout.height - imageView_' + character.name + '.height) / 2).toFloat())' + '\n' +
' .setDuration(' + character.animation.duration + ')' + '\n' +
' .start()' + '\n'

break
}
case 'left':
case 'right': {
sceneCode += ' imageView_' + character.name + '.animate()' + '\n' +
' .translationX(' + character.animation.margins.side + 'f)' + '\n' +
' .translationY(' + character.animation.margins.top + 'f)' + '\n' +
' .setDuration(' + character.animation.duration + ')' + '\n' +
' .start()' + '\n'

break
}
}

sceneCode += ' }' + '\n\n' +

' override fun onAnimationRepeat(animation: Animation?) {}' + '\n' +
' })' + '\n'
}
} else if (character.animation) {
switch (character.animation.side) {
case 'center': {
sceneCode += '\n' + ' imageView_' + character.name + '.animate()' + '\n' +
' .translationX(((frameLayout.width - imageView_' + character.name + '.width) / 2).toFloat())' + '\n' +
' .translationY(((frameLayout.height - imageView_' + character.name + '.height) / 2).toFloat())' + '\n' +
' .setDuration(1000)' + '\n' +
' .setDuration(' + character.animation.duration + ')' + '\n' +
' .start()' + '\n'

break
}
case 'left':
case 'right': {
sceneCode += '\n' + ' imageView_' + character.name + '.animate()' + '\n' +
' .translationX(' + character.animateTo.margins.side + '.toFloat())' + '\n' +
' .translationY(' + character.animateTo.margins.top + '.toFloat())' + '\n' +
' .setDuration(1000)' + '\n' +
' .translationX(' + character.animation.margins.side + 'f)' + '\n' +
' .translationY(' + character.animation.margins.top + 'f)' + '\n' +
' .setDuration(' + character.animation.duration + ')' + '\n' +
' .start()' + '\n'

break
Expand Down Expand Up @@ -772,5 +851,6 @@ export default {
addSpeech,
addSoundEffect,
addMusic,
addTransition,
finalize
}

0 comments on commit b30724a

Please sign in to comment.