I'm working on a fully-featured, basic classic RPG (JRPG) using the Android "Javascript" IDE--AndroidScript (which is great!). Here's a few questions to start off: (I'm going to ask in separate questions to get more reputation--it's hard to get in the beginning. ha)
QUESTION: I'm creating the battle text (ie "You attack for 8.\nGoblin attacks for 2."). I'm trying to use one string and add the text, depending on who goes first,separated by a new line character. However, in canvas.DrawText(string, x, y), it doesn't seem to allow "\n", and i can't fit that much text in one line on my (thus any) phone. So it would require a lot of unnecessary condition tests without using one string with the new line character. Can one insert new line characters in an image's DrawText() method?
It's excessive, but here's all the code thus far:
/*
* My first JavaScript RPG
* @author I don't care...please steal this.
*/
var enemyArray = [];
function Enemy( type, level, str, hp, totalhp, x, y, speed )
{
this.type = type;
this.level = level;
this.str = str;
this.hp = hp;
this.totalhp = totalhp;
this.exp = level * 3;
this.gold = level;
this.x = x;
this.y = y;
this.isAlive = true;
this.speed = speed;
}
var STATE = {
MAINMENU : {value: 0, name: "Main Menu", code: "M"},
WORLDMAP : {value: 1, name: "World Map", code: "W"},
BATTLE : {value: 2, name: "Battle", code: "B"},
STATUS : {value: 3, name: "Status", code: "S"},
INVENTORY : {value: 4, name: "Inventory", code: "I"},
DEAD : {value: 5, name: "Dead", code: "D"},
};
var player = {
yourTurn: true,
name : "",
x : 0.5,
y : 0.9,
level : 1,
strength : 2,
intel : 2,
totalhp : 10,
hp : 10,
totalmp : 3,
mp : 3,
level : 1,
exp : 0,
gold : 0,
inventory : [],
speed : 0.002,
playerSpeedMultiplier : 20 // it's low so that the run decision uses even sides
}
var game = {
timer : null,
isPaused : false,
quit : false,
state : STATE.MAINMENU,
level : 0,
enemies : enemyArray,
currentEnemy : null
}
var ui =
{
battleText : "",
init : function(){
//Lock screen orientation to Portrait.
app.SetOrientation( "Portrait" );
//Stop screen turning off.
app.PreventScreenLock( true );
//Create a layout with objects vertically centered.
lay = app.CreateLayout( "linear", "Vertical,FillXY" );
lay.SetBackColor( "#000000" );
//Set canvas size
var canvasHeight = 0.75;
var canvasWidth = 1.0;
//Create an blank image to act as our drawing 'canvas'.
//(For performance reasons, we limit the internal bitmap to
//480x800 and set screen updating to manual mode).
canvas = app.CreateImage( null, canvasWidth, canvasHeight, "fix", 480, 800 );
canvas.SetAutoUpdate( false );
lay.AddChild( canvas );
//Create menu button.
btnStart = app.CreateButton( "Start", 0.4 );
btnStart.SetMargins( 0, 0.02, 0, 0 );
btnStart.SetOnTouch( btn_start );
lay.AddChild( btnStart );
moveButtons = app.CreateLayout( "Linear", "Horizontal" );
lay.AddChild( moveButtons );
btnLeft = app.CreateButton( "Left", 0.2, 0.16 );
btnLeft.SetOnTouch( btn_left );
moveButtons.AddChild( btnLeft );
layVert = app.CreateLayout( "Linear", "Vertical" );
btnUp = app.CreateButton( "Up", 0.3, 0.08 );
btnUp.SetOnTouch( btn_up );
layVert.AddChild( btnUp );
btnDown = app.CreateButton( "Down", 0.3, 0.08 );
btnDown.SetOnTouch( btn_down );
layVert.AddChild( btnDown );
moveButtons.AddChild( layVert );
btnRight = app.CreateButton( "Right", 0.2, 0.16 );
btnRight.SetOnTouch( btn_right );
moveButtons.AddChild( btnRight );
btnLeft.SetVisibility( "hide" );
btnUp.SetVisibility( "hide" );
btnDown.SetVisibility( "hide" );
btnRight.SetVisibility( "hide" );
battleButtons = app.CreateLayout( "Linear", "Horizontal" );
lay.AddChild( battleButtons );
btnAttack = app.CreateButton( "Attack", 0.2, 0.16 );
btnAttack.SetOnTouch( btn_attack );
battleButtons.AddChild( btnAttack );
layMid = app.CreateLayout( "Linear", "Vertical" );
btnItem = app.CreateButton( "Item", 0.3, 0.08 );
btnItem.SetOnTouch( btn_item );
layMid.AddChild( btnItem );
btnRun = app.CreateButton( "Run", 0.3, 0.08 );
btnRun.SetOnTouch( btn_run );
layMid.AddChild( btnRun );
battleButtons.AddChild( layMid );
btnMagic = app.CreateButton( "Magic", 0.2, 0.16 );
btnMagic.SetOnTouch( btn_magic );
battleButtons.AddChild( btnMagic );
//Status button
btnStatus = app.CreateButton( "Status", 0.9, 0.025, "blue" );
btnStatus.SetOnTouch( btn_status );
lay.AddChild( btnStatus );
btnAttack.SetVisibility( "gone" );
btnItem.SetVisibility( "gone" );
btnRun.SetVisibility( "gone" );
btnMagic.SetVisibility( "gone" );
//Status slider
//Create a layout we can slide over the main layout.
laySlide = app.CreateLayout( "Linear", "FillXY" );
laySlide.SetPadding( 0, 0.1, 0, 0 );
laySlide.SetBackground( "/Sys/Img/GreenBack.png" );
laySlide.SetVisibility( "Hide" );
//Create tabs.
var tabs = app.CreateTabs( "STATUS,EQUIP,INVENTORY", 0.8, 0.8, "VCenter" );
tabs.SetOnChange( tabs_OnChange );
laySlide.AddChild( tabs );
//Create button and add to main layout.
btnBack = app.CreateButton( "Back", 0.3, 0.06, "gray" );
btnBack.SetOnTouch( btnBack_OnTouch );
laySlide.AddChild( btnBack );
btnStatus.SetVisibility( "gone" );
//Add layouts to app.
app.AddLayout( lay );
app.AddLayout( laySlide );
//Switch off debugging for max speed.
app.SetDebugEnabled( false );
},
write : function(){},
update: function(){}
}
//STATUS SLIDER
//Called when user touches our 'slide' button.
function btn_status()
{
laySlide.Animate( "SlideFromRight" );
game.isPaused = true;
}
//Called when user touches our 'back' button.
function btnBack_OnTouch()
{
laySlide.Animate( "SlideToLeft" );
game.isPaused = false;
}
//Handle tab selection.
function tabs_OnChange( name )
{
app.ShowPopup( name );
}
//Called when application is started.
function OnStart()
{
ui.init();
//Call DrawFrame function 30x a second.
game.timer = setInterval( drawFrame, 1000/30 ); // 30 default
}
//Update and redraw all game graphics.
function drawFrame()
{
//Clear the canvas.
canvas.Clear();
if(game.state == STATE.MAINMENU) {
drawMenu();
}
if(game.state == STATE.WORLDMAP) {
drawWorld();
drawChar();
drawEnemies();
areAllEnemiesDead();
}
if(game.state == STATE.BATTLE) {
drawBattleScreen();
}
if(game.state == STATE.STATUS) {
drawStatusScreen();
}
if(game.state == STATE.INVENTORY) {
drawInventory();
}
if(game.state == STATE.DEAD) {
drawDead();
}
//Update the canvas.
canvas.Update();
//Quit game if required.
if( game.quit ) return;
}
function goToNextLevel(){
game.level += 1;
player.hp = player.totalhp;
player.mp = player.totalmp;
app.ShowPopup( "Level " + game.level );
btnStart.SetVisibility("gone");
btnLeft.SetVisibility( "show" );
btnUp.SetVisibility( "show" );
btnDown.SetVisibility( "show" );
btnRight.SetVisibility( "show" );
btnAttack.SetVisibility( "gone" );
btnItem.SetVisibility( "gone" );
btnRun.SetVisibility( "gone" );
btnMagic.SetVisibility( "gone" );
canvas.SetBackColor( "#008200" );
for (var i = 0; i < game.enemies.length; i++) {
game.enemies.pop();
}
player.x = 0.5;
player.y = 0.9;
createEnemies();
game.state=STATE.WORLDMAP;
}
//Draw the Menu
function drawMenu()
{
//Draw header
canvas.SetTextSize( 14 );
canvas.SetPaintColor( "#ff0088ff" );
canvas.DrawText( "Super Best RPG,", 0.1, 0.1 );
//Draw info
canvas.SetTextSize( 16 );
canvas.SetPaintColor( "#ffff0000" );
canvas.DrawText( "Battle great moon", 0.1, 0.3 );
}
//Called when user presses 'Start' button.
function btn_start()
{
goToNextLevel();
btnStatus.SetVisibility( "show" );
}
function createEnemies(){
app.ShowPopup( "Level " + game.level );
for(var i = 0; i < game.level; i++) {
game.enemies.push(
new Enemy("Goblin",
1,
Math.pow(1.2, game.level),
5,
game.level * 5,
(Math.random() * 0.58) + 0.22,
(Math.random() * 0.89),
0.002
)
);
}
}
//Called when user presses 'up'
function btn_up()
{
if(player.y > 0.06) {
player.y -= player.speed * player.playerSpeedMultiplier;
app.Vibrate( "0,30" );
}
}
//Called when user presses 'down'
function btn_down()
{
if(player.y < 0.90) {
player.y += player.speed * player.playerSpeedMultiplier;
app.Vibrate( "0,30" );
}
}
//Called when user presses 'left'
function btn_left()
{
if(player.x > 0.23) {
player.x -= player.speed * player.playerSpeedMultiplier;
app.Vibrate( "0,30" );
}
}
//Called when user presses 'right'
function btn_right()
{
if(player.x < 0.77) {
player.x += player.speed * player.playerSpeedMultiplier;
app.Vibrate( "0,30" );
}
}
//Called when user presses 'Attack'
function btn_attack()
{
ui.battleText = "";
if(player.speed >= game.currentEnemy.speed) {
youAttack();
player.yourTurn = false;
enemyAttack();
player.yourTurn = true;
}
else {
player.yourTurn = false;
enemyAttack();
player.yourTurn = true;
youAttack();
}
}
//Called when user presses 'Item'
function btn_item()
{
ui.battleText = "";
if(player.yourTurn) {
}
}
//Called when user presses 'Run'
function btn_run()
{
ui.battleText = "";
if(player.yourTurn) {
if(player.speed >= game.currentEnemy.speed) {
game.currentEnemy.isAlive = false;
battleExit();
game.state = STATE.WORLDMAP;
}
else {
player.yourTurn = false;
enemyAttack();
player.yourTurn = true;
}
}
}
//Called when user presses 'Magic'
function btn_magic()
{
ui.battleText = "";
if(player.yourTurn) {
}
}
function drawWorld()
{
canvas.SetPaintStyle( "Fill" );
canvas.SetPaintColor( "#555500" );
canvas.DrawRectangle(0.2, 0.0, 0.8, 1.0);
//HUD
//level
canvas.SetTextSize( 24 );
canvas.SetPaintColor( "#ff22aaaa" );
canvas.DrawText( "" + game.level, 0.05, 0.1 );
//health/magic text
canvas.SetTextSize( 6 );
canvas.SetPaintColor( "#ff000000" );
canvas.DrawText( "HP: " + player.hp + "\\" + player.totalhp, 0.01, 0.95 );
canvas.DrawText( "MP: " + player.mp + "\\" + player.totalmp, 0.82, 0.95 );
//health/magic bars
canvas.SetPaintColor( "#ffff0000" );
var hpsize = (player.hp/player.totalhp) * 0.6;
canvas.DrawRectangle( 0.066, 0.9 - hpsize, 0.133 , 0.9);
canvas.SetPaintColor( "#ff0000ff" );
var mpsize = (player.mp/player.totalmp) * 0.6;
canvas.DrawRectangle( 0.866, 0.9 - mpsize, 0.933 , 0.9);
}
function drawChar()
{
//Stick man
//Head
canvas.SetPaintStyle( "Line" );
canvas.SetPaintColor( "#ff000000" );
canvas.DrawCircle( player.x, player.y, 0.02 );
//Body
canvas.SetLineWidth( 4.0 );
canvas.DrawLine( player.x, player.y + 0.01, player.x, player.y + 0.05 );
//Legs
canvas.SetLineWidth( 2.5 );
canvas.DrawLine( player.x, player.y + 0.05, player.x - 0.03, player.y + 0.08 );
canvas.DrawLine( player.x, player.y + 0.05, player.x + 0.03, player.y + 0.08 );
//Arms
canvas.DrawLine( player.x - 0.04, player.y + 0.025, player.x + 0.04, player.y + 0.025 );
}
function drawEnemies(){
canvas.SetPaintStyle( "Line" );
canvas.SetPaintColor( "#000000" );
for (var i = 0; i < game.enemies.length; i++) {
if(game.enemies[i].isAlive){
moveEnemyTowardsPlayer(game.enemies[i]);
checkEnemy(game.enemies[i]);
canvas.DrawCircle(game.enemies[i].x ,game.enemies[i].y ,0.01);
}
}
}
function moveEnemyTowardsPlayer(enemy)
{
if (game.isPaused) return;
if (enemy.x < player.x) {
enemy.x += enemy.speed;
}
if (enemy.x > player.x) {
enemy.x -= enemy.speed;
}
if (enemy.y < player.y) {
enemy.y += enemy.speed;
}
if (enemy.y > player.y) {
enemy.y -= enemy.speed;
}
}
function checkEnemy(enemy)
{
if (enemy.hp <= 0) return;
if (enemy.x > player.x - 0.03 && enemy.x < player.x + 0.03 &&
enemy.y > player.y - 0.02 && enemy.y < player.y + 0.08) {
enemy.speed = 0;
game.currentEnemy = enemy;
app.ShowPopup( game.currentEnemy.type + " Attacks!");
if(Math.random() > 0.5) yourTurn = false;
battleSetup();
game.state = STATE.BATTLE;
}
}
//BATTLE
//Hide moveButtons
//Show battleButtons
function battleSetup() {
btnLeft.SetVisibility( "gone" );
btnUp.SetVisibility( "gone" );
btnDown.SetVisibility( "gone" );
btnRight.SetVisibility( "gone" );
btnAttack.SetVisibility( "show" );
btnItem.SetVisibility( "show" );
btnRun.SetVisibility( "show" );
btnMagic.SetVisibility( "show" );
canvas.SetLineWidth(10);
canvas.SetPaintColor( "#ff777777" );
canvas.DrawLine(0, 1, 1, 1);
}
//Show moveButtons
//Hide battleButtons
function battleExit() {
btnLeft.SetVisibility( "show" );
btnUp.SetVisibility( "show" );
btnDown.SetVisibility( "show" );
btnRight.SetVisibility( "show" );
btnAttack.SetVisibility( "gone" );
btnItem.SetVisibility( "gone" );
btnRun.SetVisibility( "gone" );
btnMagic.SetVisibility( "gone" );
}
//Draw the Battle Screen
function drawBattleScreen()
{
//Draw Enemy Stats
canvas.SetLineWidth(1);
canvas.SetTextSize( 9 );
canvas.SetPaintColor( "#ff000000" );
canvas.DrawText( "" + game.currentEnemy.type +
" HP: " + game.currentEnemy.hp + "\\" + game.currentEnemy.totalhp, 0.04, 0.07 );
//Lines under enemy stats
canvas.SetLineWidth(2.5);
canvas.SetPaintColor( "#ff000000" );
canvas.DrawLine(0, 0.09, 0.25, 0.09);
canvas.SetLineWidth(2.0);
canvas.DrawLine(0, 0.10, 0.20, 0.10);
canvas.SetLineWidth(1.5);
canvas.DrawLine(0, 0.11, 0.15, 0.11);
canvas.SetLineWidth(1.0);
canvas.DrawLine(0, 0.12, 0.10, 0.12);
canvas.SetLineWidth(0.5);
canvas.DrawLine(0, 0.13, 0.05, 0.13);
//Draw Player Stats
canvas.SetLineWidth(1);
canvas.SetTextSize( 9 );
canvas.SetPaintColor( "#ff000000" );
canvas.DrawText( "HP: " + player.hp + "\\" + player.totalhp, 0.7, 0.87 );
canvas.DrawText( "MP: " + player.mp + "\\" + player.totalmp, 0.7, 0.93 );
//Draw Enemy
//Head
canvas.SetLineWidth(5);
canvas.SetPaintColor( "#ff884400" );
canvas.DrawCircle( 0.7, 0.25, 0.2 );
//Eyes
canvas.SetPaintColor( "#ff222200" );
canvas.SetLineWidth(7);
canvas.DrawLine( 0.55, 0.2, 0.64, 0.24);
canvas.DrawLine( 0.79, 0.2, 0.70, 0.24);
//Mouth
canvas.SetPaintColor( "#ff000000" );
canvas.SetLineWidth(7);
canvas.DrawLine( 0.59, 0.31, 0.75, 0.31);
canvas.DrawLine( 0.61, 0.32, 0.73, 0.32);
//Draw Player
//Head
canvas.SetLineWidth(10);
canvas.SetPaintColor( "#ff000000" );
canvas.DrawCircle( 0, 0.5, 0.25 );
//Body
canvas.SetLineWidth(20);
canvas.DrawLine(0, 0.65, 0, 1);
//Arm
canvas.DrawLine(0, 0.8, 0.4, 0.8);
//Sword
canvas.SetLineWidth(12);
canvas.DrawLine(0.35, 0.88, 0.5, 0.5);
canvas.SetLineWidth(7);
canvas.DrawLine(0.3, 0.73, 0.5, 0.78);
//BattleText
canvas.SetLineWidth(1);
canvas.DrawText(ui.battleText, 0.6, 0.7);
showOrHideButtons();
}
function showOrHideButtons() {
if(player.yourTurn) {
btnAttack.SetVisibility("Show");
btnItem.SetVisibility("Show");
btnRun.SetVisibility("Show");
btnMagic.SetVisibility("Show");
}
else {
btnAttack.SetVisibility("Hide");
btnItem.SetVisibility("Hide");
btnRun.SetVisibility("Hide");
btnMagic.SetVisibility("Hide");
}
}
function youAttack(){
if(player.hp <= 0) return;
var tempRandom = (Math.random() > 0.3);
app.ShowPopup( "str:" + player.strength + tempRandom);
if(tempRandom) {
game.currentEnemy.hp -= player.strength;
ui.battleText += "Hit for " + player.strength;
} else {
ui.battleText += "You missed";
}
checkEnemyDeath();
}
function enemyAttack(){
if(game.currentEnemy.hp <= 0) return;
if(Math.random() > 0.5) {
player.hp -= Math.floor(game.currentEnemy.str);
}
checkPlayerDeath();
}
function checkEnemyDeath() {
if(game.currentEnemy.hp <= 0) {
game.currentEnemy.isAlive == false;
player.exp += game.currentEnemy.exp;
ui.battleText = "You defeated the " + game.currentEnemy.type + "! " +
"You gained " + game.currentEnemy.exp + " exp.";
player.y += 0.01;
battleExit();
game.currentEnemy.x = 1000;
game.state = STATE.WORLDMAP;
areAllEnemiesDead();
}
}
function areAllEnemiesDead(){
var allDead = true;
for (var i = 0; i < game.enemies.length; i++) {
if(game.enemies[i].hp > 0){
allDead = false;
}
}
if (allDead) {
goToNextLevel();
}
}
function checkPlayerDeath() {
if(player.hp <= 0) {
player.isAlive == false;
player.hp = 0;
app.ShowPopup( "Died on level " + game.level );
btnStart.SetVisibility("gone");
btnLeft.SetVisibility( "gone" );
btnUp.SetVisibility( "gone" );
btnDown.SetVisibility( "gone" );
btnRight.SetVisibility( "gone" );
btnAttack.SetVisibility( "gone" );
btnItem.SetVisibility( "gone" );
btnRun.SetVisibility( "gone" );
btnMagic.SetVisibility( "gone" );
btnStatus.SetVisibility( "gone" );
canvas.SetBackColor( "#000000" );
drawFrame();
}
}
Thanks!
I'm afraid that Sebastien is correct. The DrawText method in AndroidScript internally calls the standard Android SDK Canvas.DrawText() method, which does not support multi-line output (perhaps for performance reasons).
You can see this from other people's questions about Android here:-
Draw multi-line text to Canvas
But you could try writing your own little Multi-line output function by splitting the string with the JavaScript split() method :)
I like your app by the way... it looks fun!